﻿using System.Collections.Generic;
using System.Security.Principal;

namespace Sidvall.Security
{
    public class PrincipalManager
    {
        #region Public Members

        public Sidvall.Security.IPrincipalProvider PrincipalProvider { get; set; }
        #region ClaimManager

        private ClaimManager _ClaimManager;
        public ClaimManager ClaimManager
        {
            get
            {
                if (_ClaimManager != null)
                    return _ClaimManager;
                return Sidvall.SystemContext.Current.ClaimManager;
            }
            set
            {
                _ClaimManager = value;
            }
        }

        #endregion

        #region CurrentIdentityAuthenticationType

        public string CurrentIdentityAuthenticationType
        {
            get
            {
                return GetIdentityAuthenticationType(this.CurrentPrincipal);
            }
        }

        #endregion
        #region CurrentIdentityFullName

        public string CurrentIdentityFullName
        {
            get
            {
                return GetIdentityFullName(this.CurrentPrincipal);
            }
        }

        #endregion
        #region CurrentIdentityName

        public string CurrentIdentityName
        {
            get
            {
                return GetIdentityName(this.CurrentPrincipal);
            }
        }

        #endregion
        #region CurrentIdentityIsAuthenticated

        public bool CurrentIdentityIsAuthenticated
        {
            get
            {
                if (this.PrincipalProvider == null)
                    return false;
                return GetIsAuthenticated(this.CurrentPrincipal);
            }
        }

        #endregion
        #region CurrentPrincipal

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public IPrincipal CurrentPrincipal
        {
            get
            {
                if (this.PrincipalProvider == null)
                    return null;
                return this.PrincipalProvider.CurrentPrincipal;
            }
            set
            {
                if (this.PrincipalProvider == null)
                    return;
                this.PrincipalProvider.CurrentPrincipal = value;
            }
        }

        #endregion
        #region CurrentPrincipalName

        public string CurrentPrincipalName
        {
            get
            {
                return GetPrincipalName(this.CurrentPrincipal);
            }
        }

        #endregion
        #region CurrentPrincipalNameResolved

        public string CurrentPrincipalNameResolved
        {
            get
            {
                return GetPrincipalNameResolved(this.CurrentPrincipal);
            }
        }

        #endregion

        #region AddCurrentPrincipalClaim

        public void AddCurrentPrincipalClaim(Claim claim)
        {
            if (this.CurrentPrincipal == null)
                return;
            this.ClaimManager.AddClaim(this.CurrentPrincipal.Identity, claim);
        }

        #endregion
        #region CurrentPrincipalHasClaim

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public bool CurrentPrincipalHasClaim(string claimType, string value)
        {
            if (this.CurrentPrincipal == null)
                return false;
            return this.ClaimManager.HasClaim(this.CurrentPrincipal.Identity, claimType, value);
        }

        #endregion
        #region FindCurrentPrincipalClaim

        public Claim FindCurrentPrincipalClaim(string claimType)
        {
            if (this.CurrentPrincipal == null)
                return null;
            return this.ClaimManager.FindClaim(this.CurrentPrincipal.Identity, claimType);
        }

        #endregion
        #region FindCurrentPrincipalClaims

        public ClaimCollection FindCurrentPrincipalClaims()
        {
            return FindCurrentPrincipalClaims(null);
        }
        public ClaimCollection FindCurrentPrincipalClaims(string claimType)
        {
            if (this.CurrentPrincipal == null)
                return null;
            return this.ClaimManager.FindClaims(this.CurrentPrincipal.Identity, claimType);
        }

        #endregion
        #region FindCurrentPrincipalClaimValue

        public string FindCurrentPrincipalClaimValue(string claimType)
        {
            if (this.CurrentPrincipal == null)
                return null;
            return this.ClaimManager.FindClaimValue(this.CurrentPrincipal.Identity, claimType);
        }

        #endregion
        #region FindCurrentPrincipalClientId

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public string FindCurrentPrincipalClientId()
        {
            if (this.CurrentPrincipal == null)
                return null;
            return this.ClaimManager.FindClientId(this.CurrentPrincipal.Identity);
        }

        #endregion
        #region FindCurrentPrincipalSubjectId

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public string FindCurrentPrincipalSubjectId()
        {
            if (this.CurrentPrincipal == null)
                return null;
            return this.ClaimManager.FindSubjectId(this.CurrentPrincipal.Identity);
        }

        #endregion
        #region MergeCurrentPrincipalClaim

        public void MergeCurrentPrincipalClaim(string claimType, string value)
        {
            if (this.CurrentPrincipal == null)
                return;
            this.ClaimManager.MergeClaim(this.CurrentPrincipal.Identity, claimType, value);
        }

        #endregion

        #region FindPrincipalClaim

        public Claim FindPrincipalClaim(IPrincipal principal, string claimType)
        {
            return FindPrincipalClaim(principal?.Identity, claimType);
        }
        public Claim FindPrincipalClaim(IIdentity identity, string claimType)
        {
            if (identity == null)
                return null;
            return this.ClaimManager.FindClaim(identity, claimType);
        }

        #endregion
        #region FindPrincipalClaims

        public ClaimCollection FindPrincipalClaims(IPrincipal principal, string claimType)
        {
            return FindPrincipalClaims(principal?.Identity, claimType);
        }
        public ClaimCollection FindPrincipalClaims(IIdentity identity, string claimType)
        {
            if (identity == null)
                return null;
            return this.ClaimManager.FindClaims(identity, claimType);
        }

        #endregion
        #region FindPrincipalClaimValue

        public string FindPrincipalClaimValue(IPrincipal principal, string claimType)
        {
            return FindPrincipalClaimValue(principal?.Identity, claimType);
        }
        public string FindPrincipalClaimValue(IIdentity identity, string claimType)
        {
            if (identity == null)
                return null;
            return this.ClaimManager.FindClaimValue(identity, claimType);
        }

        #endregion
        #region FindPrincipalClientId

        public string FindPrincipalClientId(IPrincipal principal)
        {
            return FindPrincipalClientId(principal?.Identity);
        }
        public string FindPrincipalClientId(IIdentity identity)
        {
            if (identity == null)
                return null;
            return this.ClaimManager.FindClientId(identity);
        }

        #endregion
        #region FindPrincipalSubjectId

        public string FindPrincipalSubjectId(IPrincipal principal)
        {
            return FindPrincipalSubjectId(principal?.Identity);
        }
        public string FindPrincipalSubjectId(IIdentity identity)
        {
            if (identity == null)
                return null;
            return this.ClaimManager.FindSubjectId(identity);
        }

        #endregion
        #region GetIdentityAuthenticationType

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public string GetIdentityAuthenticationType(IPrincipal principal)
        {
            if (principal == null)
                return string.Empty;
            return GetIdentityAuthenticationType(principal.Identity);
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public string GetIdentityAuthenticationType(IIdentity identity)
        {
            if (identity == null)
                return string.Empty;
            return identity.AuthenticationType;
        }

        #endregion
        #region GetIdentityFullName

        public string GetIdentityFullName(IPrincipal principal)
        {
            if (principal == null)
                return string.Empty;
            return GetIdentityFullName(principal.Identity);
        }
        public string GetIdentityFullName(IIdentity identity)
        {
            string authenticationType, name;

            authenticationType = GetIdentityAuthenticationType(identity);
            if (string.IsNullOrWhiteSpace(authenticationType))
                return string.Empty;
            name = GetIdentityName(identity);
            if (string.IsNullOrWhiteSpace(name))
                return string.Empty;
            return authenticationType + "." + name;
        }

        #endregion
        #region GetIdentityName

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public string GetIdentityName(IPrincipal principal)
        {
            if (principal == null)
                return string.Empty;
            return GetIdentityName(principal.Identity);
        }
        public string GetIdentityName(IIdentity identity)
        {
            if (identity == null)
                return string.Empty;
            if (!identity.IsAuthenticated)
                return string.Empty;
            if (!string.IsNullOrWhiteSpace(identity.Name))
                return identity.Name;
            var subjectId = this.ClaimManager.FindSubjectId(identity);
            if (!string.IsNullOrWhiteSpace(subjectId))
                return subjectId;
            var clientId = this.ClaimManager.FindClientId(identity);
            if (!string.IsNullOrWhiteSpace(clientId))
                return clientId;
            return string.Empty;
        }

        #endregion
        #region GetIsAuthenticated

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public bool GetIsAuthenticated(IPrincipal principal)
        {
            if (principal == null)
                return false;
            if (principal.Identity == null)
                return false;
            return principal.Identity.IsAuthenticated;
        }

        #endregion
        #region GetPrincipalName

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public string GetPrincipalName(IPrincipal principal)
        {
            if (principal == null)
                return string.Empty;
            return GetPrincipalName(principal.Identity);
        }
        public string GetPrincipalName(IIdentity identity)
        {
            return this.ClaimManager.FindName(identity);
        }

        #endregion
        #region GetPrincipalNameResolved

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public string GetPrincipalNameResolved(IPrincipal principal)
        {
            if (principal == null)
                return string.Empty;
            return GetPrincipalNameResolved(principal.Identity);
        }
        public string GetPrincipalNameResolved(IIdentity identity)
        {
            var name = GetPrincipalName(identity);
            if (!string.IsNullOrWhiteSpace(name))
                return name;
            return GetIdentityName(identity);
        }

        #endregion
        #region InitializeCurrentPrincipal

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public void InitializeCurrentPrincipal(string name, IEnumerable<Claim> items)
        {
            CustomPrincipal principal;
            CustomIdentity identity;

            principal = this.CurrentPrincipal as CustomPrincipal;
            if (principal == null)
            {
                identity = new CustomIdentity()
                {
                    IsAuthenticated = true,
                    Name = name,
                };
                principal = new CustomPrincipal(identity);
                this.ClaimManager.AddClaims(principal.Identity, items);
                this.CurrentPrincipal = principal;
                this.SetThreadPrincipal(principal);
            }
            else
            {
                identity = principal.Identity as CustomIdentity;
                if (identity == null)
                {
                    identity = new CustomIdentity()
                    {
                        IsAuthenticated = true,
                        Name = name,
                    };
                    principal.Identity = identity;
                }
                if (!identity.Name.Equals(name, System.StringComparison.OrdinalIgnoreCase))
                    identity.Name = name;
                this.ClaimManager.ClearClaims(principal.Identity);
                this.ClaimManager.AddClaims(principal.Identity, items);
            }
        }

        #endregion
        #region PrincipalHasClaim

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public bool PrincipalHasClaim(IPrincipal principal, string claimType, string value)
        {
            return PrincipalHasClaim(principal?.Identity, claimType, value);
        }
        public bool PrincipalHasClaim(IIdentity identity, string claimType, string value)
        {
            if (identity == null)
                return false;
            return this.ClaimManager.HasClaim(identity, claimType, value);
        }

        #endregion
        #region SetThreadPrincipal

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public void SetThreadPrincipal(IPrincipal principal)
        {
            if (this.PrincipalProvider == null)
                return;
            this.PrincipalProvider.SetThreadPrincipal(principal);
        }

        #endregion

        #region ToString

        public override string ToString()
        {
            return "PrincipalManager - Sidvall.Security.IPrincipalProvider";
        }

        #endregion

        #endregion
        #region Constructors

        public PrincipalManager(Sidvall.Security.IPrincipalProvider principalProvider)
        {
            this.PrincipalProvider = principalProvider;
        }
        public PrincipalManager(Sidvall.Security.IPrincipalProvider principalProvider, Sidvall.Security.ClaimManager claimManager)
        {
            this.PrincipalProvider = principalProvider;
            this.ClaimManager = claimManager;
        }

        #endregion
    }
}
